package com.logicfishsoftware.owlet.ext.pellet;

import org.mindswap.pellet.jena.PelletReasonerFactory;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.logicfishsoftware.owlet.app.Application;
import com.logicfishsoftware.owlet.app.ApplicationException;
import com.logicfishsoftware.owlet.app.Operator;
import com.logicfishsoftware.owlet.jena.JenaModelApp;
import com.logicfishsoftware.owlet.jena.JenaModelOperator;

/**
 * Hello world!
 *
 */
public class PelletJenaApplication
extends JenaModelApp<PelletJenaApplication.PelletAtom,PelletJenaApplication.PelletContext>
implements Application<PelletJenaApplication.PelletOperator>
{	
	public enum ModelType {
		ONTOMODEL, INFMODEL
	}
    /**
	 * @author logicfish@gmail.com
	 *
	 */
	public static interface PelletOperator extends JenaModelOperator<PelletContext> {
		abstract ModelType getModelType();
	}
	
	public class PelletContext extends JenaModelApp<PelletAtom,PelletContext>.JenaModelContext {

		/**
		 * @param jenaModelApp
		 * @param atomic
		 */
		protected PelletContext(
				PelletAtom atomic) {
			super(atomic);
		}
		
	}
	
	class PelletAtom extends JenaModelApp<PelletAtom,PelletContext>.JenaModelAtom {
		
		private Model model;


		/**
		 * @param delegate
		 * @throws ApplicationException 
		 */
		protected PelletAtom(PelletOperator delegate) throws ApplicationException {
			super(delegate);
		}


		/**
		 * @param proceed
		 * @throws ApplicationException 
		 */
		public PelletAtom(Operator<? super PelletContext> proceed) throws ApplicationException {
			super(proceed);
		}


		@Override
		public Model getModel() throws ApplicationException {
			if(this.model != null) 
				return this.model;
			
			PelletOperator pelletDelegate = (PelletOperator) getDelegate();
			
			switch(pelletDelegate.getModelType()) {
			case INFMODEL:
				return this.model = getInfModel();
			case ONTOMODEL:
				return this.model = getOntoModel();
			}
			throw new PelletJenaException("Invalid model type.");
		}


		/**
		 * @return
		 */
		private Model getOntoModel() {			
			Model model = getDelegate().createModel();
			
			if(model != null) 
				return ModelFactory.createOntologyModel( PelletReasonerFactory.THE_SPEC , model );
			else 
				return ModelFactory.createOntologyModel( PelletReasonerFactory.THE_SPEC );
			
		}


		/**
		 * @return
		 */
		private Model getInfModel() {
			Model model = getDelegate().createModel();
	  	    // create Pellet reasoner
	        Reasoner reasoner = PelletReasonerFactory.theInstance().create();
	        
	        // create an empty model
	        if(model==null)
	        	model = ModelFactory.createDefaultModel( );
	        
	        // create an inferencing model using Pellet reasoner
	        return ModelFactory.createInfModel( reasoner, model );
		}

		/* (non-Javadoc)
		 * @see com.logicfishsoftware.owlet.jena.JenaModelApp.JenaModelAtom#dispose()
		 */
		@Override
		public void dispose() {
			super.dispose();
			model = null;
		}
	}

	/* (non-Javadoc)
	 * @see com.logicfishsoftware.owlet.jena.JenaModelApp#createAppContext(com.logicfishsoftware.owlet.jena.JenaModelApp.JenaModelAtom)
	 */
	@Override
	protected PelletContext createAppContext(PelletAtom atomic) {
		return new PelletContext(atomic);
	}
	
	/* (non-Javadoc)
	 * @see com.logicfishsoftware.owlet.jena.JenaModelApp#createAtom(com.logicfishsoftware.owlet.app.Operator)
	 */
	@Override
	protected PelletAtom createAtom(Operator<? super PelletContext> proceed) throws ApplicationException {
		return new PelletAtom(proceed);
	}
	
	public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }

	/* (non-Javadoc)
	 * @see com.logicfishsoftware.owlet.app.Application#apply(java.lang.Object)
	 */
	public boolean enter(PelletOperator atomic) throws ApplicationException {
		return enter(new PelletAtom(atomic));
	}

}
